﻿
Public Module _interfaceOperations
    Private Function copyClone(Of valueT)(ByRef dest As valueT, ByVal src As valueT) As Boolean
        dest = DirectCast((DirectCast(src, ICloneable).Clone()), valueT)
        Return True
    End Function

    Public Function copy(Of valueT)(ByRef dest As valueT, ByVal src As valueT) As Boolean
        If isCloneable(src) Then
            Return copyClone(dest, src)
        Else
            Return eva(dest, src)
        End If
    End Function

    Public Function copy(Of T)(ByVal i As T) As T
        If i Is Nothing Then
            Return Nothing
        End If

        If isdebugmode() AndAlso Not isCloneable(i) Then
            raiseError("input is not cloneable, type " + GetType(T).FullName, errorHandle.errorType.exclamation)
        End If
        Dim rtn As T = Nothing
        copy(rtn, i)
        Return rtn
    End Function

    Public Function containsInterface(Of T)(ByVal interfaceName As String) As Boolean
        Dim i As T = Nothing
        i = alloc(Of T)()
        Return containsInterface(i, interfaceName)
    End Function

    Public Function containsInterface(Of T)(ByVal this As T, ByVal interfaceName As String) As Boolean
        If Not this Is Nothing Then
#If PocketPC OrElse Smartphone Then
            Dim i As System.Collections.IEnumerator = this.GetType.GetInterfaces.GetEnumerator()
            Dim found As Boolean = False
            While i.MoveNext
                If CType(i.Current, Type).Name = interfaceName Then
                    found = True
                    Exit While
                End If
            End While
            Return found
#Else
            Dim tp As Type = this.GetType().GetInterface(interfaceName, True)
            Return Not tp Is Nothing
#End If
        Else
            Return False
        End If
    End Function

    Public Function istype(Of T2, T)(ByVal this As T) As Boolean
        Return Not this Is Nothing AndAlso TypeOf this Is T2
    End Function

    Public Function istype(Of T)(ByVal this As Object) As Boolean
        Return istype(Of T, Object)(this)
    End Function

    Public Function isCloneable(Of T)(ByVal this As T) As Boolean
#If RETIRED Then
        Return containsInterface(this, "ICloneable")
        Return Not this Is Nothing AndAlso TypeOf this Is ICloneable
#End If
        Return istype(Of ICloneable, T)(this)
    End Function

    Public Function isCloneable(Of T)() As Boolean
        Dim this As T = Nothing
        this = alloc(Of T)()
        Return isCloneable(this)
    End Function

    Public Function isComparable(Of T)(ByVal this As T) As Boolean
#If RETIRED Then
        Return containsInterface(this, "IComparable")
        Return Not this Is Nothing AndAlso TypeOf this Is IComparable
#End If
        Return istype(Of IComparable, T)(this)
    End Function

    Public Function isComparable(Of T, CompareTo)(ByVal this As T) As Boolean
        Return istype(Of IComparable(Of CompareTo), T)(this)
    End Function

    Public Function isComparable(Of T)() As Boolean
        Dim this As T = Nothing
        this = alloc(Of T)()
        Return isComparable(this)
    End Function

    Public Function isComparable(Of T, CompareTo)() As Boolean
        Dim this As T = Nothing
        this = alloc(Of T)()
        Return isComparable(this)
    End Function

    Public Const object_compare_undetermined As SByte = 2

    Public Function object_compare(ByVal this As Object, ByVal that As Object) As SByte
        If Object.ReferenceEquals(this, that) Then
            Return 0
        ElseIf this Is Nothing Then
            Return -1
        ElseIf that Is Nothing Then
            Return 1
        Else
            Return object_compare_undetermined
        End If
    End Function

    Private Sub compare_error(Of T, T2)(ByVal ex As Exception)
        raiseError("caught exception when comparing " + _
                   GetType(T).FullName() + " with " + GetType(T2).FullName() + _
                   ", ex " + ex.Message + ", callstack " + ex.StackTrace(), errorHandle.errorType.exclamation, _
                   additionaljump:=1)
    End Sub

    Private Function compareImpl(Of T, T2)(ByVal this As T, ByVal that As T2) As Int32
        'try IComparable(Of T2) first, otherwise to IComparable
        Dim this2 As IComparable(Of T2) = Nothing
        If convertor.cast(Of IComparable(Of T2))(this, this2) Then
            Try
                Return this2.CompareTo(that)
            Catch ex As Exception
                compare_error(Of T, T2)(ex)
                Return npos
            End Try
        Else
            Return compareImpl(Of T)(this, that)
        End If
    End Function

    Private Function compareImpl(Of T)(ByVal this As T, ByVal that As Object) As Int32
        'try IComparable first, otherwise raise error
        Dim this2 As IComparable = Nothing
        If convertor.cast(Of IComparable)(this, this2) Then
            Try
                Return this2.CompareTo(that)
            Catch ex As Exception
                compare_error(Of T, Object)(ex)
                Return npos
            End Try
        Else
            raiseError("caught instance do not have IComparable implement or is nothing, unable to compare. " + _
                       GetType(T).FullName, errorHandle.errorType.exclamation)
            Return npos
        End If
    End Function

    Public Function cast_compare(Of T, T2, CompT)(ByVal this As T, ByVal that As T2) As Int32
        Dim cmp As SByte
        cmp = object_compare(this, that)
        If cmp = object_compare_undetermined Then
            Return compareImpl(Of T, CompT)(this, convertor.cast(Of CompT)(that))
        Else
            Return cmp
        End If
    End Function

    Public Function compare(Of T, T2 As CompT, CompT)(ByVal this As T, ByVal that As T2) As Int32
        Dim cmp As SByte
        cmp = object_compare(this, that)
        If cmp = object_compare_undetermined Then
            Return compareImpl(Of T, CompT)(this, that)
        Else
            Return cmp
        End If
    End Function

    Public Function compare(Of T, T2)(ByVal this As T, ByVal that As T2) As Int32
        Dim cmp As SByte
        cmp = object_compare(this, that)
        If cmp = object_compare_undetermined Then
            Return compareImpl(Of T, T2)(this, that)
        Else
            Return cmp
        End If
    End Function

    Public Function compare(Of T)(ByVal this As T, ByVal that As Object) As Int32
        Dim cmp As SByte
        cmp = object_compare(this, that)
        If cmp = object_compare_undetermined Then
            Return compareImpl(Of T)(this, that)
        Else
            Return cmp
        End If
    End Function

    Public Function equals(Of T, T2)(ByVal this As T, ByVal that As T2) As Boolean
        Return compare(this, that) = 0
    End Function

    Public Function equals(Of T)(ByVal this As T, ByVal that As T) As Boolean
        Return compare(Of T, T)(this, that) = 0
    End Function

    Public Function equals(Of T)(ByVal this As T, ByVal that As Object) As Boolean
        Return compare(Of T)(this, that) = 0
    End Function

    Private Delegate Function compareDelegate(Of T, T2)(ByVal this As T, ByVal that As T2) As Int32

    Private Function operatorEqualImpl(Of T, T2)(ByVal this As T, ByVal that As T2, _
                                                 ByVal compare As compareDelegate(Of T, T2)) As Boolean
        assert(Not compare Is Nothing, "compare is a nothing compareDelegate.")
        If this Is Nothing AndAlso that Is Nothing Then
            Return True
        ElseIf this Is Nothing OrElse that Is Nothing Then
            Return False
        Else
            Return compare(this, that) = 0
        End If
    End Function

    'save a call to compare(Of T,T2), and IComparable(Of Object)
    Public Function operatorEqual(Of T)(ByVal this As T, ByVal that As Object) As Boolean
        Return operatorEqualImpl(this, that, AddressOf compare(Of T))
    End Function

    Public Function operatorUnequal(Of T)(ByVal this As T, ByVal that As Object) As Boolean
        Return Not operatorEqual(this, that)
    End Function

    Public Function operatorEqual(Of T, T2)(ByVal this As T, ByVal that As T2) As Boolean
        Return operatorEqualImpl(this, that, AddressOf compare(Of T, T2))
    End Function

    Public Function operatorUnequal(Of T, T2)(ByVal this As T, ByVal that As T2) As Boolean
        Return Not operatorEqual(this, that)
    End Function

    Private Function operatorLessImpl(Of T, T2)(ByVal this As T, ByVal that As T2, _
                                                ByVal compare As compareDelegate(Of T, T2)) As Boolean
        assert(Not compare Is Nothing)
        If this Is Nothing AndAlso that Is Nothing Then
            Return False
        ElseIf this Is Nothing Then
            Return True
        ElseIf that Is Nothing Then
            Return False
        Else
            Return compare(this, that) < 0
        End If
    End Function

    Public Function operatorLess(Of T)(ByVal this As T, ByVal that As Object) As Boolean
        Return operatorLessImpl(this, that, AddressOf compare(Of T))
    End Function

    Public Function operatorMore(Of T)(ByVal this As T, ByVal that As Object) As Boolean
        Return Not operatorLess(this, that)
    End Function

    Public Function operatorLess(Of T, T2)(ByVal this As T, ByVal that As T2) As Boolean
        Return operatorLessImpl(this, that, AddressOf compare(Of T, T2))
    End Function

    Public Function operatorMore(Of T, T2)(ByVal this As T, ByVal that As T2) As Boolean
        Return Not operatorLess(this, that)
    End Function

#If RETIRED Then
    'this inherit terribly decrease the performance
    Public MustInherit Class IComparable2
        Implements IComparable

        Public Shared Operator <>(ByVal this As IComparable2, ByVal that As IComparable2) As Boolean
            Return Not this = that
        End Operator

        Public Shared Operator =(ByVal this As IComparable2, ByVal that As IComparable2) As Boolean
            If this Is Nothing AndAlso that Is Nothing Then
                Return True
            ElseIf this Is Nothing OrElse that Is Nothing Then
                Return False
            Else
                Return compare(this, that)
            End If
        End Operator

        Public MustOverride Function CompareTo(ByVal obj As Object) As Int32 Implements System.IComparable.CompareTo
    End Class

    Public MustInherit Class IComparable2(Of T)
        Inherits IComparable2

        Public MustOverride Overloads Function CompareTo(ByVal that As T) As Int32

        Public NotOverridable Overrides Function CompareTo(ByVal obj As Object) As Int32
            Dim that As T = Nothing
            that = convertor.cast(Of T)(obj)

            Return CompareTo(that)
        End Function
    End Class
#End If
End Module
